package com.lebang.service.task.impl;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lebang.common.util.AmountUtil;
import com.lebang.common.util.ShowDateUtil;
import com.lebang.component.RedisClient;
import com.lebang.component.RedisSdkClient;
import com.lebang.entity.RequestHeaders;
import com.lebang.entity.member.LbbMember;
import com.lebang.entity.member.LbbMemberRecord;
import com.lebang.entity.task.LbbCommon;
import com.lebang.entity.task.TaskScreenshot;
import com.lebang.example.LbbCommonExample;
import com.lebang.mapper.*;
import com.lebang.mapper.buss.multiword.MultiwordSpeechMapper;
import com.lebang.mapper.buss.multiword.MultiwordSpeechPlanMapper;
import com.lebang.model.TaskInitModel;
import com.lebang.model.enums.Booleans;
import com.lebang.model.enums.Status;
import com.lebang.model.enums.TaskEnableResultEnum;
import com.lebang.model.enums.buss.RecordStatus;
import com.lebang.model.enums.buss.TaskCategory;
import com.lebang.model.enums.buss.TaskStatus;
import com.lebang.model.enums.buss.UserStatus;
import com.lebang.model.recordback.RecordCallBack;
import com.lebang.model.taskback.CommonCallBack;
import com.lebang.model.taskback.Detail;
import com.lebang.model.taskback.Record;
import com.lebang.model.vo.buss.TaskSearchVo;
import com.lebang.model.vo.buss.multiword.MultiwordSpeech;
import com.lebang.model.vo.buss.multiword.MultiwordSpeechPlan;
import com.lebang.service.MemberNoticeService;
import com.lebang.service.TaskInRedisService;
import com.lebang.service.buss.MemberRecordService;
import com.lebang.service.buss.WalletService;
import com.lebang.service.task.TaskService;
import com.lebangweb.common.DateUtil;
import com.lebangweb.common.TextUtil;
import com.lebangweb.common.UUIDUtil;
import com.lebangweb.response.Callback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.*;

import static com.lebang.service.task.impl.MultiwordServiceImpl.TASK_MULTIWORD_AMOUNT;

/**
 * 通用任务
 *
 * @author weizx
 * @className CommonService
 * @date 2018年8月22日 上午11:42:21
 */
@Service(value = "commonTaskService")
@Slf4j
public class CommonServiceImpl implements TaskService<LbbCommon> {
    private static final String TASK_COMMON_AMOUNT = "task_common_amount";

    @Autowired
    private TaskInRedisService taskInRedisService;
    @Autowired
    private WalletService walletService;

    @Autowired
    private LbbMemberMapper lbbMemberMapper;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private MemberNoticeService memberNoticeService;
    @Autowired
    private MemberRecordService memberRecordService;

    @Autowired
    protected LbbCommonMapper lbbCommonMapper;

    @Autowired
    private LbbMemberRecordMapper lbbMemberRecordMapper;
    @Autowired
    private MultiwordSpeechPlanMapper multiwordSpeechPlanMapper;
    @Autowired
    private MultiwordSpeechMapper multiwordSpeechMapper;

    @Autowired
    private TaskScreenshotMapper taskScreenshotMapper;
    @Autowired
    private TaskTagRelationMapper taskTagRelationMapper;
    @Autowired
    private RedisSdkClient redisSdkClient;


    @Override
    public List<RecordCallBack> showListForApp(String memberId, Integer page, Integer size, String brand, Integer showHomePage, String imei, String params) {
        return null;
    }

    @Override
    public List<LbbCommon> taskList(Integer page, Integer limit) {
        LbbCommonExample example = new LbbCommonExample();
        if(!TextUtil.isEmpty(page,limit)){
            example.setOffset((long) ((page-1)*limit));
            example.setLimit(limit);
        }
        return lbbCommonMapper.selectByExample(example);
    }


    @Override
    public TaskEnableResultEnum checkTaskEnableDoForUser(String taskid, String imei, String userid) {

        LbbCommon lbbCommon = lbbCommonMapper.getByTaskId(taskid);
        if (lbbCommon == null || lbbCommon.getStatus().equals(Status.Off)) {
            return TaskEnableResultEnum.FAIL_NOT_EXITS;
        }
        if (!TextUtil.isEmpty(lbbCommon.getTaskCategory())) {
            LbbMember member = lbbMemberMapper.getMemberByMemberId(userid);
            List<String> taskCategoryList = lbbCommonMapper.selectTaskCategoryList(member.getPhone());
            for (String next : taskCategoryList) {
                if (lbbCommon.getTaskCategory().equals(next)) {
                    TaskEnableResultEnum enableResultEnum = TaskEnableResultEnum.FAIL_TASK_END;
                    enableResultEnum.setMsg("[" + lbbCommon.getTaskCategory() + "]系列任务你已完成过了");
                    return enableResultEnum;
                }
            }
        }
        if (lbbCommon.getWaitCount() != 0 && lbbCommon.getWaitTime() != 0) {
            if (taskInRedisService.checkRedBookFiter(userid)) {
                return TaskEnableResultEnum.FAIL_TASK_END;
            }
        }
        if (lbbCommon.getLessTime() != 0) {
            if (taskInRedisService.checkRedBookByTaksId(taskid)) {
                return TaskEnableResultEnum.FAIL_TASK_END;
            }
        }
        return TaskEnableResultEnum.SUCCESS;
    }


    @Override
    public RecordStatus pull(String memberId, LbbCommon task, RequestHeaders requsetHeader, String orderid, String taskId) {

        // redis 里查看任务量
        int count = taskInRedisService.getTaskAmount(TASK_COMMON_AMOUNT, task.getTaskId());
        if (count <= 0) {
            return RecordStatus.OUT_OF_STOCK;
        }
        // 获取任务量完成情况

        // 用户是否做过
        LbbMemberRecord record = memberRecordService.checkRecord(memberId, task.getTaskId(), TaskCategory.Common.name());

        if (record != null) {
            return RecordStatus.EXIST;
        }
        //领取成功redis任务量-1
        taskInRedisService.taskAmountSubtract(TASK_COMMON_AMOUNT, task.getTaskId());
        int t = memberRecordService.insertRecord(TaskCategory.Common, task.getTaskId
                        (), memberId, requsetHeader, TaskStatus.WaitSumbit, "",
                orderid, Booleans.True, 0, AmountUtil.checkAmount(task), task.getIncrease(), task.getType(), task.getTitle());
        //监听任务30分钟释放
        taskInRedisService.recordAdd(t, task.getReleaseTime());
        //已领取数量+1
        if (task.getWaitTime() != 0 && task.getWaitCount() != 0) {
            long pullCount = taskInRedisService.recordAddRedBook(task.getTaskId());
            if (pullCount >= task.getWaitCount()) {
                taskInRedisService.addCheckRedBookByTaksId(task.getTaskId(), task.getWaitTime());
            }
        }
        return RecordStatus.PULL_SUCCESS;
    }

    @Override
    public RecordStatus push(String memberId, LbbMemberRecord record, LbbCommon task, String result, Integer sex) {
        record.setResult(result);
        record.setSubmitTime(new Date());
        if (sex != null) {
            record.setSex(sex);
        }
        /*提交任务修改状态*/
        if (task.getNeedCheck().equals(Booleans.True.name())) {
            record.setStatus(TaskStatus.WaitCheckout);
            String desc = "恭喜！任务“{title}”已提交，小姐姐正在努力审核!";
            desc = desc.replace("{title}", task.getTitle());
            memberNoticeService.notice(record, TaskCategory.Common.getTitle(), desc);

            int i = memberRecordService.updateByPrimaryKeySelective(record);
            if (i == 0) {
                return RecordStatus.FAIL;
            }
        } else {
            List<String> id = new ArrayList<>(1);
            id.add(record.getId().toString());
            this.examineAndVerify(id, "", "任务成功", "",1);
        }
        if (record.getRedo() != null) {
            if (record.getRedo() == 0) {
                taskInRedisService.recordDel(record.getId().intValue());
            }
        }
        if (task.getLessTime() != 0) {
            taskInRedisService.addRedBookFiter(memberId, task.getLessTime());
        }
        return RecordStatus.PUSH_SUCCESS;
    }

    @Override
    public RecordStatus redo(String memberId, LbbMemberRecord record, LbbCommon task) {
        if (record.getRedo() == null) {
            record.setRedo(0);
        }
        TaskScreenshot taskScreenshot = taskScreenshotMapper.selectByTaskId(task.getTaskId());
        if(taskScreenshot!=null){
            if(taskScreenshot.getFailTimes()!=-1&&taskScreenshot.getFailTimes()<=(record.getRedo())){
                return RecordStatus.REDO_MAX;
            }
        }


        record.setRedo(record.getRedo()+1);
        record.setStatus(TaskStatus.WaitSumbit);
        record.setCreateTime(new Date());
        taskInRedisService.recordAdd(record.getId().intValue());
        record.setHurryTime(null);
        record.setSubmitTime(new Date());
        record.setResult("");
        memberRecordService.updateByPrimaryKeySelective(record);
        if(task.getIsMultiword()==0){
            taskInRedisService.taskAmountSubtract(TASK_COMMON_AMOUNT, task.getTaskId());
        }else {
            taskInRedisService.taskAmountSubtract(TASK_MULTIWORD_AMOUNT, record.getOrderId());
        }

        //已领取数量+1
        if(task.getWaitTime()!=0&&task.getWaitCount()!=0){
            long pullCount = taskInRedisService.recordAddRedBook(task.getTaskId());
            if (pullCount >= task.getWaitCount()) {
                taskInRedisService.addCheckRedBookByTaksId(task.getTaskId(), task.getWaitTime());
            }
        }
        return RecordStatus.REDO_SUCCESS;
    }

    @Override
    public RecordStatus urgentTask(String memberId, LbbMemberRecord record, LbbCommon task) {
        List<String> id = new ArrayList<>(1);
        id.add(record.getId().toString());
        this.examineAndVerify(id, "", "任务成功", "",1);
        return RecordStatus.CALL_SUCCESS;

    }

    @Override
    public LbbCommon taskInfoByTaskId(String taskId) {
        return lbbCommonMapper.getByTaskId(taskId);
    }

    @Override
    public LbbCommon taskInfoById(Integer id) {
        return lbbCommonMapper.selectByPrimaryKey(id.longValue());
    }

    @Override
    public CommonCallBack taskDetail(LbbCommon task, LbbMemberRecord record, LbbMember member, String orderId) throws Exception {
        CommonCallBack commonCallBack = new CommonCallBack();

        Record reco = new Record();
        Detail detail = new Detail();
        JSONArray aa = JSONArray.parseArray(task.getContents());
        detail.setContents(aa);
        // 获取任务量完成情况
        int amount = taskInRedisService.getTaskAmount(TASK_COMMON_AMOUNT, task.getTaskId());

        // 判断用户是否做过
        String userStatus = UserStatus.Allow.name();
        if (record != null) {
            // 如果做过不允许再做
            commonCallBack.setCreatTime(DateUtil.dateToString(record.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            userStatus = UserStatus.Disallow.name();
            if (!record.getStatus().equals(TaskStatus.WaitSumbit)) {
                commonCallBack.setMemberResult(JSONArray.parseArray(record.getResult()));
            }
            commonCallBack.setType(record.getRewordType());
            commonCallBack.setUserMoney(record.getUserMoney());
        } else {
            record = new LbbMemberRecord();
            record.setCreateTime(new Date());
            record.setStatus(TaskStatus.None);
            commonCallBack.setType(task.getType().getIndex());
            commonCallBack.setUserMoney(AmountUtil.checkAmount(task));
        }
        if (!TextUtil.isEmpty(task.getMission())) {
            List<String> stringList = Arrays.asList(task.getMission().split("#"));
            detail.setIsMission(true);
            detail.setMissionList(stringList);
        }

        detail.setPkg(task.getPkg());
        detail.setAmount(amount);
        detail.setIcon(task.getIcon());
        detail.setTitle(task.getTitle());
        detail.setLabel(task.getLabel());
        detail.setType(task.getType());
        detail.setMedia(task.getMedia());
        detail.setUserStatus(userStatus);

        if (TextUtil.isEmpty(task.getPkg())) {
            detail.setPackagename("");
        } else {
            detail.setPackagename(task.getPkg());
        }
        reco.setEndTime(ShowDateUtil.afterMinute(record.getCreateTime(), task.getReleaseTime()));
        reco.setResult(record.getResult() == null ? "" : record.getResult());
        reco.setStatus(record.getStatus().name());
        reco.setRemark(record.getRemark());
        reco.setSubmitTime(record.getSubmitTime() == null ? "" : DateUtil.dateToString(record.getSubmitTime(), "yyyy-MM-dd HH:mm:ss"));
        commonCallBack.setCategory(TaskCategory.Common.name());
        commonCallBack.setTaskid(task.getTaskId());
        commonCallBack.setTaskTime(task.getTaskTime());
        commonCallBack.setAuditTime(task.getAuditTime());
        commonCallBack.setRedoStatus(task.getRedo());
        if (task.getRedo() == null) {
            task.setRedo(0);
        }
        if (record.getHurryTime() == null) {

            commonCallBack.setHurryTime(0);
        } else {
            commonCallBack.setHurryTime(1);
        }
        if (record.getRedo() == null) {
            record.setRedo(0);
        }
        if (record.getSubmitTime() != null && record.getCreateTime() != null) {
            commonCallBack.setOverTime(ShowDateUtil.getDatePoor(record.getSubmitTime(), record.getCreateTime()));
        } else {
            commonCallBack.setOverTime("0");
        }
        commonCallBack.setRedocount(record.getRedo());
        commonCallBack.setRecord(reco);
        commonCallBack.setDetail(detail);
        return commonCallBack;
    }

    @Override
    public int insertTask(LbbCommon task) {
        task.setCreateTime(new java.util.Date());
        task.setHasDeleted(Booleans.False.name());
        return lbbCommonMapper.insertSelective(task);
    }

    @Override
    public int updateTask(LbbCommon task) {
        return lbbCommonMapper.updateByPrimaryKeySelective(task);
    }

    @Override
    public int deleteTask(LbbCommon task) {
        task.setHasDeleted("True");
        return lbbCommonMapper.updateByPrimaryKeySelective(task);
    }

    @Override

    public int examineAndVerify(List<String> list, String tab, String status, String remark,Integer multiple) {
        String uuid = UUIDUtil.M();
        //boolean lock = redisClient.tryGetDistributedLock("lock:common", uuid, 30000);
        boolean lock = redisSdkClient.tryGetDistributedLock("lock:common", uuid, 30000);
        try {
            if (!lock) {
                return -1;
            }
            List<LbbMemberRecord> recordList = lbbMemberRecordMapper.findCheckListByid(list);
            for (LbbMemberRecord record : recordList) {
                if (record.getStatus().equals(TaskStatus.CheckSuccess)) {
                    continue;
                }
                record.setStatus(TaskStatus.getByTitle(status));
                LbbCommon task = this.taskInfoByTaskId(record.getTaskId());
                record.setStatus(TaskStatus.getByTitle(status));
                if (record.getStatus().equals(TaskStatus.CheckFailure)) {
                    record.setRemark(remark);
                }
                record.setCheckTime(new Date());
                memberRecordService.updateByPrimaryKeySelective(record);
                if (record.getStatus().equals(TaskStatus.CheckSuccess)) {
                    // 计算奖励
                    Integer amount;
                    if (record.getUserMoney().equals(0)) {
                        amount = AmountUtil.checkAmount(task);
                    } else {
                        amount = record.getUserMoney();
                    }
                    if (task.getIsMultiword() == 1) {
                        MultiwordSpeech multiwordSpeech = multiwordSpeechMapper.selectByPrimaryKey(Long.parseLong(record.getOrderId()));
                        if (multiwordSpeech.getHasPlan() == 1) {
                            String str = DateUtil.dateToString(record.getCreateTime(), "yyyyMMdd");
                            MultiwordSpeechPlan plan = multiwordSpeechPlanMapper.getmultiwordSpeech(multiwordSpeech.getId(), str);
                            if (plan != null) {
                                plan.setTadayTotal(plan.getTadayTotal() + 1);
                                multiwordSpeechPlanMapper.updateByPrimaryKeySelective(plan);
                            }
                            multiwordSpeech.setAllTotal(multiwordSpeech.getAllTotal() + 1);
                            multiwordSpeech.setTadayTotal(multiwordSpeech.getTadayTotal() + 1);
                            multiwordSpeechMapper.updateByPrimaryKeySelective(multiwordSpeech);
                        } else {
                            multiwordSpeech.setAllTotal(multiwordSpeech.getAllTotal() + 1);
                            multiwordSpeech.setTadayTotal(multiwordSpeech.getTadayTotal() + 1);
                            multiwordSpeechMapper.updateByPrimaryKeySelective(multiwordSpeech);
                        }
                    }
                    walletService.income(record.getMemberId(), record, TaskCategory.Common, record.getTaskId(), task.getTitle(), amount*multiple);
                    task.setSuccessCount(task.getSuccessCount() + 1);
                    task.setTodayAmount(task.getTodayAmount() + 1);
                    memberNoticeService.notice(record, task.getTitle(), "任务通知:提交的任务审核成功!");
                } else {
                    task.setFailCount(task.getFailCount() + 1);
                    memberNoticeService.notice(record, task.getTitle(), "对不起，您提交的不符合要求，审核失败!");
                    //审核失败解除用户的过滤
                    taskInRedisService.cleanRedBookFiter(record.getMemberId());
                }
                this.updateTask(task);
            }
            return 1;
        } catch (Exception e) {
            e.printStackTrace();

            return 0;
        } finally {
            //redisClient.releaseDistributedLock("lock:common", uuid);
            redisSdkClient.releaseDistributedLock("lock:common", uuid);
        }

    }


    @Override
    public Map<String, Object> list(TaskSearchVo vo) {
        return null;
    }


    @Override
    public Boolean exportTaskRecode(String taskId, OutputStream outputStream, List<TaskStatus> taskStatusList) {


        LbbCommon lbbCommon = lbbCommonMapper.getByTaskId(taskId);
        if (lbbCommon == null) {
            return false;
        }
        String contents = lbbCommon.getContents();

        ExcelWriter writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX, true);
        Sheet sheet1 = new Sheet(1, 0);
        sheet1.setSheetName("第一个sheet");
        List<LbbMemberRecord> records = new ArrayList<>();
        for (TaskStatus t : taskStatusList) {
            records.addAll(memberRecordService.getRecord(taskId, t, TaskCategory.Common));
        }
        // 设置标题
        Table table = new Table(1);
        List<List<String>> titles = new ArrayList<>();
        titles.add(Collections.singletonList("审核结果"));
        titles.add(Collections.singletonList("任务时间"));
        titles.add(Collections.singletonList("手机号"));
        titles.add(Collections.singletonList("设备标识"));

        table.setHead(titles);
        List<List<String>> datalist = new ArrayList<>();

        boolean isAddHead = false;
        int step = 1;
        for (LbbMemberRecord record : records) {
            LbbMember member = lbbMemberMapper.getMemberByMemberId(record.getMemberId());
            List<String> item = new ArrayList<>();

            item.add(record.getStatus().getTitle());
            item.add(DateUtil.dateToString(record.getCreateTime(), "yyyy-MM-dd HH:mm"));
            item.add(member.getPhone());
            item.add(record.getImei());

            String result = record.getResult();
            JSONArray jsonArrayResult = JSONArray.parseArray(result);

            for (Object oresult : jsonArrayResult) {
                JSONObject rt = (JSONObject) oresult;
                if ("image".equals(rt.getString("type"))) {
                    item.add(rt.getJSONObject("resultImage").getString("image"));

                } else if ("input".equals(rt.getString("type"))) {
                    item.add(rt.getJSONObject("resultInput").getString("image"));
                }
                if (!isAddHead) {
                    titles.add(Collections.singletonList("步骤" + step + "-" + rt.getString("type")));
                }
                step += 1;
            }
            isAddHead = true;
            datalist.add(item);
        }

        writer.write0(datalist, sheet1, table);
        writer.finish();

        return true;
    }

    @Override
    public void releaseTask(LbbMemberRecord record) {
        //返还任务
        LbbCommon lbbCommon = lbbCommonMapper.getByTaskId(record.getTaskId());
        String title = "通用任务释放通知";
        String desc = "任务通知【" + lbbCommon.getTitle() + "】未在规定时间内完成,已被释放,请重新领取!";
        memberNoticeService.notice(record, title, desc);
        String date = DateUtil.dateToString(new Date(), "yyyyMMdd");
        String creatdate = DateUtil.dateToString(record.getCreateTime(), "yyyyMMdd");
        if (date.equals(creatdate)) {
            taskInRedisService.taskAmountAdd(TASK_COMMON_AMOUNT, record.getTaskId());
        }
    }

    /**
     * 加载每日任务方法
     *
     * @return
     */
    @Override
    public boolean starTaskAmount(LocalDateTime dateTime) {
        LbbCommonExample example = new LbbCommonExample();
        example.createCriteria().andStatusEqualTo("On").andHasDeletedEqualTo(Booleans.False.name()).andIsMultiwordEqualTo(0);
        List<LbbCommon> commons = lbbCommonMapper.selectByExample(example);
        //redisClient.del(TASK_COMMON_AMOUNT);
        redisSdkClient.del(TASK_COMMON_AMOUNT);
        List<TaskInitModel> taskInitModels = new ArrayList<>();
        commons.forEach(vo -> {
            TaskInitModel model = new TaskInitModel();
            model.setTaskId(vo.getTaskId());
            model.setAmount(vo.getAmount());
            model.setSuccessTotal(vo.getSuccessCount());
            model.setTodayTotal(vo.getTodayAmount());
            model.setTotal(vo.getTotal());
            taskInitModels.add(model);
        });
        return taskInRedisService.taskInitByTaskModelList(TASK_COMMON_AMOUNT, taskInitModels, TaskCategory.Common, dateTime);
    }

    /**
     * 重载单个任务并且校准成功数
     *
     * @param task
     * @return
     */
    @Override
    public boolean taskInitByTaskId(LbbCommon task) {
        int i = lbbMemberRecordMapper.getsuccess(task.getTaskId(), TaskCategory.Common.name());
        int k = lbbMemberRecordMapper.getfail(task.getTaskId(), TaskCategory.Common.name());
        task.setSuccessCount(i);
        task.setFailCount(k);
        lbbCommonMapper.updateByPrimaryKeySelective(task);
        TaskInitModel model = new TaskInitModel();
        model.setTaskId(task.getTaskId());
        model.setAmount(task.getAmount());
        model.setSuccessTotal(task.getSuccessCount());
        model.setTodayTotal(task.getTodayAmount());
        model.setTotal(task.getTotal());
        return taskInRedisService.taskInitByTaskModel(TASK_COMMON_AMOUNT, model, LocalDateTime.now());
    }
}